package typejump;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;

import typejump.units.Length;
import typejump.units.Unit;

/**
 * This class loads in the variables stored in settings.txt and
 * provides methods to retrieve them conveniently.
 * @author g
 *
 */
public class Settings {

	
	private Hashtable<String, String> vars = new Hashtable<String, String>();
	private boolean loaded = false;
	
	
	
	private String[] filePaths = {
			"settings.txt",
			
			System.getProperty("user.home")
			+ File.separator
			+ ".SwaggerTyper"
			+ File.separator 
			+ "settings.txt"
	};
	private static final Object SYNC = new Object();
	
	private static Settings inst;
	
	private Settings() {
		loaded = load();
	}
	
	private boolean load() {
		synchronized (SYNC) {
			BufferedReader in = null;
			try {
				for (String path : filePaths) {
					File f = new File(path);
					if (f.exists()) {
						in = new BufferedReader(new FileReader(f));
						break;
					}
				}
				if (in == null) {
					in = new BufferedReader(
						new InputStreamReader(
								Settings.class.getResource("/typejump/res/settings.txt").openStream()));
				}
			} catch (IOException e) {
	
			}
			
			if (in == null) return false;
			
			String reads = null;
			do {
				try { reads = in.readLine(); }
				catch (IOException e) { break; }
				
				if (reads != null) {
					if (reads.startsWith("#")) continue;
					if (reads.matches(".*?#.*")) {
						reads = reads.substring(0, reads.lastIndexOf('#'));
					}
					
					if (reads.trim().length() == 0) continue;
					
					String[] parts = reads.split("=");
					if (parts.length == 2) {
						vars.put(parts[0].trim(), parts[1].trim());
					}
				}
				
			} while (reads != null);
			
			return true;
		}
	}
	
	public static boolean isLoaded() {
		synchronized (Settings.SYNC) {
			return inst != null && inst.loaded;
		}
	}
	
	public static boolean reload() {
		synchronized (Settings.SYNC) {
			if (inst == null) inst = new Settings();
			return inst.loaded = inst.load();
		}
	}
	
	/**
	 * Returns the String with the given name
	 * @param key
	 * @return
	 */
	public static String get(String key) {
		synchronized (Settings.SYNC) {
			if (inst == null) inst = new Settings();
			if (inst.vars.containsKey(key))
				return inst.vars.get(key);
			return "";
		}
	}
	
	/**
	 * Sets the given setting (not used much)
	 * @param key
	 * @param value
	 */
	public static void set(String key, Object value) {
		synchronized (Settings.SYNC) {
			if (inst == null) inst = new Settings();
			inst.vars.put(key, value.toString());
		}
	}
	
	/**
	 * Tries to parse the value at the key and return its double value. 
	 * This converts any units to pixels (eg, 30m = <n>px).
	 * @param key
	 * @return - a double value, or 0 if there is a parsing error.
	 */
	public static double getDouble(String key) {
		String v = get(key);
		
		Unit unit = null;
		if (v.matches("[-]?\\d+(\\.\\d+)?[ ]?[a-zA-Z]+")) {
			boolean dot = false;
			int nend;
			for (nend = 0; nend < v.length(); nend++) {
				char c = v.charAt(nend);
				if (nend == 0 && c == '-') continue;
				if (c >= '0' && c <= '9') continue;
				if (c == '.') {
					if (dot) break;
					dot = true;
					continue;
				}
				break;
			}
			String uName = v.substring(nend).trim();
			unit = Length.findUnit(uName);
			v = v.substring(0, nend).trim();
		}
		
		if (v.matches("[-]?\\d+(\\.\\d+)?")) {
			double d = Double.parseDouble(v);
			if (key.contains("drop")) System.out.println(key + " = " + d);
			if (unit != null) {
				d = unit.toUnit(d, Length.getDefault());
			}
			if (key.contains("drop")) System.out.println(key + " > " + d);
			return d;
		}
		return 0;
	}
	
	/**
	 * Returns the integer value at the given key, or 0
	 * if there is a parsing error.
	 * @param key
	 * @return
	 */
	public static int getInt(String key) {
		String value = get(key);
		if (value.matches("[-]?\\d+"))
			return Integer.parseInt(value);
		if (value.matches("[-]?\\d+(\\.\\d+)?[ ]?[a-zA-Z]+"))
			return (int)getDouble(key);
		if (value.matches("[-]?[0-9A-Fa-f]+"))
			return Integer.parseInt(value, 16);
		if (value.matches("[x#][-]?[0-9A-Fa-f]+"))
			return Integer.parseInt(value.substring(1), 16);
		if (value.matches("0x[-]?[0-9A-Fa-f]+"))
			return Integer.parseInt(value.substring(2), 16);
		return 0;
	}
	
	/**
	 * Returns true if the value at the given key is a boolean "true" or a positive number.
	 * @param key
	 * @return
	 */
	public static boolean test(String key) {
		String s = get(key);
		return s.equalsIgnoreCase("true") || getDouble(key) > 0;
	}
}
